package com.danicsoft.daide.serverclient;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.danicsoft.daide.command.MapDefinitionCommand;
import com.danicsoft.daide.command.NowCommand;
import com.danicsoft.daide.command.OrderCommand;
import com.danicsoft.daide.command.OrderSpec;
import com.danicsoft.daide.command.SupplyOwnershipCommand;
import com.danicsoft.daide.command.Turn;
import com.danicsoft.daide.command.UnitPos;
import com.danicsoft.daide.token.InvalidTokenException;
import com.danicsoft.daide.token.StandardToken;
import com.danicsoft.daide.token.TokenGroup;
import com.danicsoft.daide.token.TokenMap;
import com.danicsoft.daide.token.TokenMap.Coasts;

import dip.order.Order;
import dip.order.OrderFactory;
import dip.order.Orderable;
import dip.order.result.OrderResult;
import dip.order.result.OrderResult.ResultType;
import dip.process.Adjudicator;
import dip.process.StdAdjudicator;
import dip.world.Coast;
import dip.world.InvalidWorldException;
import dip.world.Power;
import dip.world.Province;
import dip.world.Unit;
import dip.world.World;
import dip.world.WorldFactory;
import dip.world.variant.data.Variant;

/**
 * A server that uses the jDip backend for adjudication.
 * @author Daniel Yule (daniel.yule@gmail.com)
 * @version 1.0
 *
 */
public class jDipServer extends DaideServer {

	/**
	 * The variant information for the current game.
	 */

	private Variant myVariant;

	/**
	 * The current state of the world.
	 */
	private World myWorld;

	/**
	 * The adjudicator we are going to use to play.
	 */
	private Adjudicator myAdjudicator;

	/**
	 * The powers that are playing in this game.
	 */
	private Power[] powers;

	/**
	 * The token mapping to be used for this game.
	 */
	private TokenMap myMapping;

	/**
	 * Construct a new jDip server using the given variant
	 * @param variantInfo
	 * @throws InvalidWorldException
	 */
	public jDipServer(Variant variantInfo) throws InvalidWorldException {
		myVariant = variantInfo;
		myWorld = WorldFactory.getInstance().createWorld(myVariant);
		myAdjudicator = new StdAdjudicator(OrderFactory.getDefault(), myWorld.getLastTurnState());
		powers = myWorld.getMap().getPowers();
	}

	@Override
	protected NowCommand armyPosition() {

		List<UnitPos> unitPositions = new ArrayList<UnitPos>();
		Province[] provinces = myWorld.getLastTurnState().getPosition().getUnitProvinces();

		for (int j = 0; j < provinces.length; j++) {
			try {
				Unit thisUnit = myWorld.getLastTurnState().getPosition().getUnit(provinces[j]);
				UnitPos thisPos = new UnitPos();
				thisPos.power = myMapping.convert(thisUnit.getPower().getName());
				thisPos.province = myMapping.convert(provinces[j].getShortName());
				Coast thisCoast = thisUnit.getCoast();
				if (thisCoast.getIndex() > 3) {
					TokenGroup groupie = new TokenGroup();
					groupie.add(thisPos.province);
					thisPos.province = groupie;
					byte coastByte = Coasts.NCS;
					switch (thisCoast.getIndex()) {
						case 4:
							coastByte = Coasts.NCS;
							break;
						case 5:
							coastByte = Coasts.SCS;
							break;
						case 6:
							coastByte = Coasts.WCS;
							break;
						case 7:
							coastByte = Coasts.ECS;
							break;
					}
					groupie.add(TokenMap.getCoastalToken(coastByte));
				}
			}
			catch (InvalidTokenException e) {

			}

		}

		return new NowCommand(currentTurn(), unitPositions);

	}

	@Override
	protected Turn currentTurn() {
		// TODO Automatically generated
		return null;
	}

	@Override
	protected MapDefinitionCommand mapDefinition() {
		// TODO Automatically generated
		return null;
	}

	@Override
	protected String mapName() {
		return myWorld.getVariantInfo().getMapName();
	}

	@Override
	protected void nextTurn() {
	// TODO Automatically generated

	}

	@Override
	protected List<StandardToken> powers() {
		List<StandardToken> rList = new ArrayList<StandardToken>();
		for(int i = 0; i < powers.length; i++) {
			try {
				rList.add(myMapping.convert(powers[i].getName()));
			}
			catch (InvalidTokenException e) {
				
			}
		}
		return rList;
	}
	

	@Override
	protected List<OrderCommand> processOrders(Set<OrderSpec> orders) {
		Map<Power, List<Order>> orderMap = new HashMap<Power, List<Order>>();
		for(OrderSpec order: orders) {
			StandardToken powerToken = order.UnitPos.power;
			Power power = Adapter.DAIDEtojDip.convertPower(powerToken, myWorld);
			
			Order aOrder = Adapter.DAIDEtojDip.convertOrder(order, power, myWorld);
			
			List<Order> orderList = myWorld.getLastTurnState().getOrders(power);
			if(orderList == null) {
				orderList = new ArrayList<Order>();
				myWorld.getLastTurnState().setOrders(power, orderList);
			}
			orderList.add(aOrder);
		}

		
		myAdjudicator.process();
		List<OrderCommand> results = new LinkedList<OrderCommand>();
		OrderCommand curOrder = null;
		Orderable resultOrder;
		OrderSpec curSpec = null;
		for(Object obj : myWorld.getLastTurnState().getResultList()) {
			OrderResult result = (OrderResult) obj;
			ResultType rType = result.getResultType();
			
			if(rType.equals(ResultType.CONVOY_PATH_TAKEN)) {
				try {
					resultOrder = result.getOrder();
					curOrder = new OrderCommand(curSpec, TokenMap.Results.SUC, getCurrentTurnInfo().turn);
				}
				catch (IllegalServerStateException e) {
					e.printStackTrace();
				}
			}
			results.add(curOrder);
		}
		
		return results;
	}

	@Override
	protected void startGame() {
	// TODO Automatically generated

	}

	@Override
	protected SupplyOwnershipCommand supplyOwnership() {
		// TODO Automatically generated
		return null;
	}

	@Override
	protected VariantInfo variantInfo() {
		// TODO Automatically generated
		return null;
	}

}
